-- ECE 251 Team B Transit Subsystem
-- This class defines a buffer for frames being moved out of the shared memory
-- April 9, 2007

Library ieee;
Use ieee.std_logic_1164.all;
Use work.transmit_package.all;

Entity FrameBuffer Is
	Port( Clock									: In Std_logic;
		  FSMinitialize							: In Std_logic;
		  FSMincomingBytes						: In Std_logic;
		  FSMnibble0							: In Std_logic_vector(3 downto 0);
		  FSMnibble1							: In Std_logic_vector(3 downto 0);
		  FSMnibble2							: In Std_logic_vector(3 downto 0);
		  FSMnibble3							: In Std_logic_vector(3 downto 0);
		  FSMfinished							: In Std_logic; 
		  MIIreadOut							: In Std_logic;
		  MIIframeReady							: Out Std_logic;
		  MIIdoneReadOut						: Out Std_logic;
		  MIInextNibble							: Out Std_logic_vector(3 downto 0);
		  bufferFull							: Buffer Std_logic;
		  readOut								: Buffer Std_logic;
		  ready									: Buffer Std_logic
	);
End FrameBuffer;

Architecture Behavior Of FrameBuffer Is

Constant Zeros		: Std_logic_vector(3 downto 0) := "0000";
Constant One		: Integer := 1;
Constant Max		: Integer := 36;--3036;
--Type Integer Is Range 1 To 3037;
-- These act as pointers to the front and back of the array, they will contain at most a single bit of 1 in a given location
-- Max frame size is 3036 Nibbles or 1518 Bytes
Signal pointer_to_back	: Integer;
Signal MoveAll			: Std_logic;
Signal NewData			: Std_logic;
--Signal GetPointer		: Std_logic;
Signal moveBack			: Std_logic;
--30
Type vectorArray Is Array(35 downto 0) Of Std_logic_vector(3 downto 0);
Signal nibblemove		: vectorArray;

Signal choice1			: Std_logic_vector(3 downto 0);
Signal choice2			: Std_logic_vector(3 downto 0);

Begin
	Process
	Begin
		Wait Until Clock'Event And Clock = '1';
		
		If FSMinitialize = '1' Then
			pointer_to_back <= 1;
			MoveAll <= '0';
			NewData <= '0';
			--NewPointerNext <= '0';
			--GetPointer <= '0';
			--GetPointerNext <= '0';
			moveBack <= '0';
			bufferFull <= '0';
			readOut <= '0';
			ready <= '0';
			choice1 <= "0000";
			choice2 <= "0000";
		End If;
		
		If FSMincomingBytes = '1' And bufferFull = '0' Then
			NewData <= '1';
			moveBack <= '1';
		Else
			NewData <= '0';
			moveBack <= '0';
		End If;	
		
		If MIIreadOut = '1' Or readOut = '1' Then
			--GetPointer <= '1';
			--pointer_to_back <= forward(pointer_to_back);
			If pointer_to_back = 1 Then
				readOut <= '0';
				ready <= '0';
			Else
				readOut <= '1';
				pointer_to_back <= pointer_to_back - 1;
			End If;
			MoveAll <= '1';
		Else
			--GetPointer <= '0';
			MoveAll <= '0';
		End If;
		
		If moveBack = '1' Then
			--pointer_to_back <= backward(pointer_to_back);
			pointer_to_back <= pointer_to_back + 4;
		End If;
		
		--If pointer_to_back = "10000000000000000" Then
		--3037
		If pointer_to_back = 37 Then
			bufferFull <= '1';
		Else
			bufferFull <= '0';
		End If;
		
		--If pointer_to_back = "00000000000000001" Then
		If pointer_to_back = 1 Then
			MIIdoneReadOut <= '1';
		Else
			MIIdoneReadOut <= '0';
		End If;
		
		If FSMfinished = '1' Then
			ready <= '1';
		End If;
		
		MIIframeReady <= ready;

		choice1(0) <= equal(pointer_to_back, One);
		choice1(1) <= '0';
		choice1(2) <= '0';
		choice1(3) <= '0';
		
		choice2(0) <= equal(pointer_to_back, Max);
		choice2(1) <= equal(pointer_to_back + 1, Max);
		choice2(2) <= equal(pointer_to_back + 2, Max);
		choice2(3) <= equal(pointer_to_back + 3, Max);
			
	End Process;
	
	nibble0: framenibble Port Map(nibblemove(0), Clock, MoveAll, (choice1(0) Or choice1(1) Or choice1(2) Or choice1(3)) And NewData, choice1, FSMnibble0, FSMnibble1, FSMnibble2, FSMnibble3, MIInextNibble);
	--30
	nibble_array: For i In 1 To 35 Generate
	Signal choice 		: Std_logic_vector(3 downto 0);
	Begin	
		choice(0) <= equal(pointer_to_back, i);
		choice(1) <= equal(pointer_to_back + 1, i);
		choice(2) <= equal(pointer_to_back + 2, i);
		choice(3) <= equal(pointer_to_back + 3, i);
		nibble: framenibble Port Map(nibblemove(i), Clock, MoveAll, (choice(0) Or choice(1) Or choice(2) Or choice(3)) And NewData, choice, FSMnibble0, FSMnibble1, FSMnibble2, FSMnibble3,  nibblemove(i-1));
	End Generate nibble_array;
	--30
	nibble36: framenibble Port Map(Zeros, Clock, MoveAll, (choice2(0) Or choice2(1) Or choice2(2) Or choice2(3)) And NewData, choice2, FSMnibble0, FSMnibble1, FSMnibble2, FSMnibble3, nibblemove(35)); 
End Behavior;